package com.glink.manage.service.Impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glink.common.contants.BaseCodeConstants;
import com.glink.common.exception.GeneralSimpleException;
import com.glink.common.util.BaseCommonUtils;
import com.glink.manage.common.BeanKit;
import com.glink.manage.domain.CodeBean;
import com.glink.manage.dto.code.*;
import com.glink.manage.mapper.CodeMapper;
import com.glink.manage.service.CodeService;
import com.glink.manage.vo.code.CodeBaseVO;
import com.glink.manage.vo.code.CodeTreeVo;
import com.glink.manage.vo.code.CodeVO;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.stream.Collectors.toList;

/**
 * @class: code
 * @author: qiushaoshan
 * @since: 2025-01-07
 * @description: 代码实现类
 */
@Service
public class CodeServiceImpl extends ServiceImpl<CodeMapper, CodeBean> implements CodeService {

    static final String LIMIT_1 = " LIMIT 1 ";
    static final String FALSE = BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02, TRUE = BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01;
    static final List<String> BOOL_LIST = Arrays.asList(FALSE, TRUE);
    private boolean isOneOrZero(String status) {
        return nonNull(status) && BOOL_LIST.contains(status);
    }

    /**
     * 查询所有代码
     * @return 代码列表
     */
    @Override
    public List<CodeVO> getLeafList() {
        List<CodeBean> codeBeanList = this.lambdaQuery()
                .eq(CodeBean::getIsLeaf, TRUE)
                .list();

        return beanListToVoList(codeBeanList);
    }
  
    /**
     * 实体转VO
     * @param codeBean code实体
     * @return vo
     */
    private CodeVO beanToVO(CodeBean codeBean){
        CodeVO codeVO = new CodeVO();
        BeanKit.copyProperties(codeBean, codeVO);
        return codeVO;
    }

    /**
     * bean数组转VO数组
     * @param codeBeanList bean数组
     * @return  vo数组
     */
    private List<CodeVO> beanListToVoList(List<CodeBean> codeBeanList){
        List<CodeVO> codeVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(codeBeanList)){
            codeBeanList.forEach(codeBean -> {
                CodeVO codeVO = beanToVO(codeBean);
                codeVOList.add(codeVO);
            });
        }
        return codeVOList;
    }

    /**
     * 根据父节点类型查询code
     * @param codeType 子节点类型
     * @param visible 是否可见
     * @return 代码列表
     */
    @Override
    public List<CodeVO> findByType(String codeType, String visible) {
        boolean isUse = nonNull(codeType);
        List<CodeBean> codeBeanList = this.lambdaQuery()
                .eq(isUse, CodeBean::getParentType, codeType)
                .eq(isOneOrZero(visible), CodeBean::getIsVisible, visible)
                .orderByAsc(CodeBean::getSeq)
                .orderByAsc(CodeBean::getType)
                .orderByAsc(CodeBean::getId)
                .list();
        return beanListToVoList(codeBeanList);
    }
    
    /**
     * 上升or下降
     * @param srcId 第一个代码ID
     * @param tgtId 第二个代码ID
     * @return 状态
     * @throws GeneralSimpleException 异常信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean upAndDown(String srcId, String tgtId) throws GeneralSimpleException {
        CodeBean src = this.getById(srcId);
        if (nonNull(src)) {
            CodeBean tgt = this.getById(tgtId);
            if (nonNull(tgt)) {
                int srcSeq = src.getSeq();
                int tgtSeq = tgt.getSeq();
                // up || down
                if (srcSeq > tgtSeq || srcSeq < tgtSeq) {
                    if (baseMapper.upAndDown(srcId, tgtId) != 2) {
                        throw new GeneralSimpleException("200001", "数据库操作失败");
                    }
                    return true;
                } else {
                    throw new GeneralSimpleException("400001", "只支持上升和下降操作");
                }
            }
        }
        return true;
    }

    /**
     * 根据代码类型删除代码
     * @param id 代码ID
     * @return 删除状态
     */
    @Override
    public boolean deleteById(String id) {
        return this.lambdaUpdate()
                .eq(CodeBean::getId, id)
                .eq(CodeBean::getIsFixed, FALSE)
                .remove();
    }

    @Override
    public List<CodeVO> findLeftTree() {
        List<CodeBean> codeBeanList = this.lambdaQuery()
                .eq(CodeBean::getIsLeaf, FALSE)
                .eq(CodeBean::getIsVisible, TRUE)
                .list();
        List<CodeVO> codeVOList = beanListToVoList(codeBeanList);
        codeVOList.forEach(codeVO -> {
            if(StringUtils.isBlank(codeVO.getParentType())){
                codeVO.setIsCanAddChild(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02);
            }else{
                int num = this.lambdaQuery()
                        .eq(CodeBean::getParentType, codeVO.getType())
                        .eq(CodeBean::getIsLeaf, FALSE).count();
                if(num > 0){
                    codeVO.setIsCanAddChild(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02);
                }
            }
        });
        
        return codeVOList;
    }

    /**
     * 代码新增
     * @param dto 新增信息
     * @return 新增状态
     * @throws GeneralSimpleException 异常信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean insert(CodeAddDTO dto) throws GeneralSimpleException {
        final String parentType = dto.getParentType();
        
        // 判断code有没有被占用
        final CodeBean parent = this.lambdaQuery()
                .eq(CodeBean::getType, parentType)
                .last(LIMIT_1).one();
        if (isNull(parent)) {
            throw new GeneralSimpleException("400002", "代码新增失败,没有父代码类型");
        }
        
//        if (TRUE.equals(parent.getIsFixed())) {
//            // 代码类型[{0}]为系统预定义项，不可新增
//            throw new GeneralSimpleException("400003", parentType);
//        }
        
        // 查询同级别的，是否存在为左侧的，如果存在，则不能新增
        checkIsCanAddChild(parentType);

        final CodeBean self = this.lambdaQuery()
                .eq(CodeBean::getParentType, parentType)
                .eq(CodeBean::getKey, dto.getKey())
                .last(LIMIT_1).one();
        if (nonNull(self)) {
            // 代码值[{0}]存在相同，不可重复新增
            throw new GeneralSimpleException("400004", dto.getKey());
        }

        CodeBean codeBean = new CodeBean();
        BeanUtils.copyProperties(dto, codeBean);
        codeBean.setIsFixed(FALSE);
        codeBean.setIsVisible(TRUE);
        codeBean.setIsLeaf(TRUE);
        // 查询序号
        CodeBean lastSeq = this.lambdaQuery()
                .eq(CodeBean::getParentType, parentType)
                .orderByDesc(CodeBean::getSeq)
                .last(LIMIT_1).one();
        if (isNull(lastSeq)) {
            codeBean.setSeq(1);
        } else {
            Integer seq = lastSeq.getSeq();
            if(Objects.isNull(seq)){
                codeBean.setSeq(1);
            }else{
                codeBean.setSeq(seq > 0 ? seq + 1 : 1);    
            }
        }

        codeBean.setParentType(dto.getParentType());
        codeBean.setType(dto.getParentType() + formatNumber(codeBean.getSeq()));
        codeBean.setId(BaseCommonUtils.generateUUID());
        return this.save(codeBean);
    }

    /**
     * 序号，左加0
     * @param number 数字
     * @return 补全的值
     */
    private String formatNumber(int number) {
        return String.format("%02d", number);
    }

    private void checkIsCanAddChild(String parentType) throws GeneralSimpleException {
        if(StringUtils.isBlank(parentType)){
            throw new GeneralSimpleException("400003", "");
        }
        int num = this.lambdaQuery()
                .eq(CodeBean::getParentType, parentType)
                .eq(CodeBean::getIsLeaf, FALSE).count();
        if(num > 0){
            throw new GeneralSimpleException("400003", parentType);
        }
    }
    
    /**
     * 新增子代码
     * @param dto 代码信息
     * @return 新增状态
     * @throws GeneralSimpleException 异常信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean insertSubCode(CodeSubCodeAddDTO dto) throws GeneralSimpleException {

        String parentType = dto.getParentType();
        final CodeBean parent = this.lambdaQuery()
                .eq(CodeBean::getType, parentType)
                .one();
        
        if (Objects.isNull(parent)){
            // 新增失败,没有父类型：[{0}]
            throw new GeneralSimpleException("400005", parentType);
        }
        
//        if (TRUE.equals(parent.getIsFixed())) {
//            // 代码类型[{0}]为系统预定义项，不可新增
//            throw new GeneralSimpleException("400003", parentType);
//        }

        // 查询同级别的，是否存在为左侧的，如果存在，则不能新增
        checkIsCanAddChild(parentType);
        
        final CodeBean self = this.lambdaQuery()
                .eq(CodeBean::getParentType, parentType)
                .eq(CodeBean::getKey, dto.getKey())
                .last(LIMIT_1).one();
        if (nonNull(self)) {
            // 代码值[{0}]存在相同，不可重复新增
            throw new GeneralSimpleException("400004", dto.getKey());
        }

        CodeBean codeBean = new CodeBean();
        BeanUtils.copyProperties(dto, codeBean);
        codeBean.setIsFixed(FALSE);
        codeBean.setIsVisible(TRUE);
        codeBean.setIsLeaf(TRUE);
        CodeBean lastSeq = this.lambdaQuery()
                .eq(CodeBean::getParentType, parentType)
                .orderByDesc(CodeBean::getSeq)
                .last(LIMIT_1).one();
        if (isNull(lastSeq)) {
            codeBean.setSeq(1);
        } else {
            final int seq = lastSeq.getSeq();
            codeBean.setSeq(seq > 0 ? seq + 1 : 1);
        }
        
        codeBean.setParentType(dto.getParentType());
        codeBean.setType(dto.getParentType() + formatNumber(codeBean.getSeq()));

        return this.save(codeBean);
    }

    /**
     * 更新子代码
     * @param dto 代码信息
     * @return 更新状态
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean updateSubCode(CodeSubCodeUpdateDTO dto) throws GeneralSimpleException {
        final String id = dto.getId();
        CodeBean one = this.lambdaQuery()
                .eq(CodeBean::getId, id)
                .one();
        if (isNull(one)) {
            // 更新失败,没有找到代码项：[{0}]
            throw new GeneralSimpleException("400006", id);
        }
        if (TRUE.equals(one.getIsFixed())) {
            // 代码类型[{0}]为系统预定义项，不可新增
            throw new GeneralSimpleException("400003", one.getKey());
        }
        final CodeBean self = this.lambdaQuery()
                .eq(CodeBean::getParentType, one.getParentType())
                .eq(CodeBean::getKey, dto.getKey())
                .ne(CodeBean::getId, one.getId())
                .last(LIMIT_1).one();
        if (nonNull(self)) {
            // 代码值[{0}]存在相同，不可重复更新
            throw new GeneralSimpleException ("400007", dto.getKey());
        }
        BeanUtils.copyProperties(dto, one, BaseCommonUtils.getNullPropertyNames(dto));
        one.setIsFixed(FALSE);
        one.setIsLeaf(TRUE);
        return lambdaUpdate()
                .eq(CodeBean::getId, id)
                .update(one);
    }

    /**
     * 根据父级类型和键值查询类别名称
     *
     * @param parentType 父级类型
     * @param key        键值
     */
    @Override
    public String findNameByParentTypeAndKey(String parentType, String key) {
        String name = "";
        CodeBean codeBean = this.lambdaQuery().eq(CodeBean::getParentType, parentType)
                .eq(CodeBean::getKey, key).one();
        if(Objects.nonNull(codeBean)){
            name = codeBean.getName();
        }

        return name;
    }

    /**
     * 根据类别查询code码值
     *
     * @param codeTypeList code
     * @return code信息
     */
    @Override
    public List<CodeVO> findByTypeList(List<String> codeTypeList) {
        List<CodeBean> codeBeanList = Lists.newArrayList();
        
        if(CollectionUtils.isNotEmpty(codeTypeList)){
            codeBeanList = this.lambdaQuery()
                    .in(CodeBean::getParentType, codeTypeList)
                    .orderByAsc(CodeBean::getParentType)
                    .orderByAsc(CodeBean::getSeq)
                    .orderByAsc(CodeBean::getType)
                    .orderByAsc(CodeBean::getId)
                    .list();
        }
       
        return beanListToVoList(codeBeanList);
    }

    /**
     * 修改代码类型
     * @param dto 代码信息
     * @return 修改状态
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean modify(CodeUpdateDTO dto) throws GeneralSimpleException {

        final String id = dto.getId();
        CodeBean one = this.lambdaQuery()
                .eq(CodeBean::getId, id)
                .one();
        if (isNull(one)) {
            // 更新失败,没有找到代码项：[{0}]
            throw new GeneralSimpleException("400006", id);
        }
        if (TRUE.equals(one.getIsFixed())) {
            // 代码类型[{0}]为系统预定义项，不可新增
            throw new GeneralSimpleException("400003", one.getKey());
        }
        final CodeBean self = this.lambdaQuery()
                .eq(CodeBean::getParentType, one.getParentType())
                .eq(CodeBean::getKey, dto.getKey())
                .ne(CodeBean::getId, one.getId())
                .last(LIMIT_1).one();
        if (nonNull(self)) {
            // 代码值[{0}]存在相同，不可重复更新
            throw new GeneralSimpleException ("400007", dto.getKey());
        }
        BeanUtils.copyProperties(dto, one, BaseCommonUtils.getNullPropertyNames(dto));
        one.setIsFixed(FALSE);
        one.setIsLeaf(TRUE);
        return lambdaUpdate()
                .eq(CodeBean::getId, id)
                .update(one);
    }

    /**
     * 根据条件查询代码信息
     * @param dto 条件信息
     * @return 代码信息
     */
    @Override
    public List<CodeBaseVO> findByCondition(CodeQueryDTO dto) {

        final String type = dto.getType();
        final String parentType = dto.getParentType();
        final String key = dto.getKey();
        final String name = dto.getName();
        return this.lambdaQuery()
                .eq(nonNull(type), CodeBean::getType, type)
                .eq(nonNull(parentType), CodeBean::getParentType, parentType)
                .eq(nonNull(key), CodeBean::getKey, key)
                .like(StringUtils.isNotEmpty(name), CodeBean::getName, name)
                .select(CodeBean::getId, CodeBean::getName, CodeBean::getType, CodeBean::getParentType, CodeBean::getKey)
                .list()
                .stream()
                .map(x -> {
                    CodeBaseVO vo = new CodeBaseVO();
                    BeanUtils.copyProperties(x, vo);
                    return vo;
                }).collect(toList());
    }

    /**
     * 根据条件查询代码项(包括子代码)
     * @param dto 查询条件
     * @return 查询结果
     */
    @Override
    public List<CodeTreeVo> findLeafTreeByCondition(CodeSubCodeQueryDTO dto) {
        return this.baseMapper.findLeafTreeByCondition(dto);
    }
}
